package com.djl.seckilldemo.controller;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.djl.seckilldemo.pojo.*;
import com.djl.seckilldemo.rabbitmq.MQSender;
import com.djl.seckilldemo.service.IGoodsService;
import com.djl.seckilldemo.service.IOrderService;
import com.djl.seckilldemo.service.ISeckillOrderService;
import com.djl.seckilldemo.vo.GoodsVo;
import com.djl.seckilldemo.vo.RespBean;
import com.djl.seckilldemo.vo.RespBeanEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  前端控制器
 * </p>
 *  功能描述：秒杀
 * @author jobob
 * @since 2021-10-22
 */

//windows 优化前3,424.658
//linux 优化前23.523
@Slf4j
@Controller
@RequestMapping("/seckill")
public class SeckillGoodsController implements InitializingBean {
    @Autowired
   private IGoodsService goodsService;
    @Autowired
    private ISeckillOrderService seckillOrderService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private RedisTemplate    redisTemplate;
    @Autowired
    private MQSender mqSender;
    private Map<Long,Boolean> emptystockMap=new HashMap<>();
    @Autowired
    private RedisScript<Long> redisScript;
    @ResponseBody
    @RequestMapping(value = "/{path}/doSeckill",method = RequestMethod.POST)
    public RespBean doSeckill(@PathVariable String path, User user,  Long goodsId){
        if (user==null){
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        Boolean check=orderService.checkPath(user,goodsId,path);
            if (!check){
                return  RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
            }

        //判断是否重复抢购
        SeckillOrder seckillOrder = (SeckillOrder)redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId);
        if (seckillOrder!=null){
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }
        //通过内存标记减少redis的使用
        if (emptystockMap.get(goodsId)){
            return  RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        //具有原子性，递减,并获取递减之后的库存
        Long stock = redisTemplate.opsForValue().decrement("seckillGoods:" + goodsId);
        //Long stock=(Long) redisTemplate.execute(redisScript, Collections.singletonList("seckillGoods:"+goodsId),Collections.EMPTY_LIST);
        if(stock<0){
            emptystockMap.put(goodsId,true);
            redisTemplate.opsForValue().increment("seckillGoods:" + goodsId);
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        SeckillMessage seckillMessage = new SeckillMessage(user, goodsId);
        mqSender.sendSeckillMsg(JSON.toJSONString(seckillMessage));

        return RespBean.success(0);



        /*
        //判断库存
        GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
        if (goods.getSeckillCount()<1){
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        //判断是否重复抢购
        SeckillOrder seckillOrder = (SeckillOrder)redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId);
        if (seckillOrder!=null){
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }
        Order order=orderService.seckill(user,goods);

        return RespBean.success(order);
           */


    }



    @RequestMapping("/doSeckill2")
    public String doSeckill2(Model model, User user,  Long goodsId){
        if (user==null){
            return "login";
        }
        model.addAttribute("user",user);
        GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
        if (goods.getSeckillCount()<1){
            model.addAttribute("errmsg", RespBeanEnum.EMPTY_STOCK.getMessage());
            return "secKillFail";
        }
        SeckillOrder seckillOrder = seckillOrderService.getOne(new QueryWrapper<SeckillOrder>().eq("user_id", user.getId())
                .eq("goods_id", goodsId),false);
        if (seckillOrder!=null){
            model.addAttribute("errmsg",RespBeanEnum.REPEATE_ERROR.getMessage());
            return "secKillFail";
        }
        Order order=orderService.seckill(user,goods);
        model.addAttribute("order",order);
        model.addAttribute("goods",goods);
        return "orderDetail";

    }
/**
 *     初始化执行的方法:把系统商品库存加载到redis

 */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> list= goodsService.findGoodsVo();
        if (CollectionUtils.isEmpty(list)){
            return;
        }
        list.forEach(goodsVo -> {

            redisTemplate.opsForValue().set("seckillGoods:"+goodsVo.getId(),goodsVo.getSeckillCount());
            emptystockMap.put(goodsVo.getId(),false);
        });
    }

    /**
     * orderId成功， 0排队中 -1失败
     * @param user
     * @param goodsId
     * @return
     */
    @RequestMapping(value = "/result",method = RequestMethod.GET)
    @ResponseBody
    public RespBean getResult(User user,Long goodsId){
        log.info("result:"+user);
        log.info("goodsId:"+goodsId);

        if(user==null){
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        Long orderId=seckillOrderService.getResult(user,goodsId);
        log.info("orderId:"+orderId);

        return  RespBean.success(orderId);
    }

    @RequestMapping(value = "/path",method = RequestMethod.GET)
    @ResponseBody
    public RespBean getPath (User user, Long goodsId, HttpServletRequest request){


        if (user==null|| StringUtils.isEmpty(goodsId)){
            return  RespBean.error(RespBeanEnum.SESSION_ERROR);
        }

        //限制访问次数，五秒内访问五次
        String requestURI = request.getRequestURI();
        Integer count = (Integer) redisTemplate.opsForValue().get(requestURI + ":" + user.getId());
        if (count==null){
            redisTemplate.opsForValue().set(requestURI + ":" + user.getId(),1,5, TimeUnit.SECONDS);
        }else if (count<5){
            redisTemplate.opsForValue().increment(requestURI + ":" + user.getId());
        }else {
            return RespBean.error(RespBeanEnum.ACCESS_LIMIT_REAHCED);
        }

        String path= orderService.createPath(user,goodsId);
        return RespBean.success(path);
    }



}
